#include<iostream>
using namespace std;

//一、再谈构造函数
//构造函数除了10_里面的，还能这样进行初始化
//1.初始化列表            ----并且使用的时候和正常方式一样
//并且只有构造函数和拷贝构造函数能使用
//列表初始化，   ：后面相当于变量进行定义的地方        这个地方就是初始化列表，专门用来初始化的           ----初始化列表-成员变量定义的地方
//class A
//{
//public:
//    A(int a)//默认的构造函数就是不传参也能调用，这样显式的定义出来传参的系统就不会自动的调用这个构造函数
//    {
//        _a=a;
//    }
//private:
//    int _a;
//};



//class data
//{
//public:
////    data(int year=1,int month=1,int day=1)//看好使用的格式是怎么样的    : , , ！！！！并且不在大括号里面，后面没有;的结束符
////        :_year(year)
////        ,_month(month)
////        ,_day(day)//并且上面的参数每个只能出现一次，可以不出现，但是不能重复出现
////        ,_N(10)//只有在链表
////    {}
//
////    data(int year=1,int month=1,int day=1)    错误的N的初始化方式
////    {
////        _year=year;
////        _month=month;
////        _day=day;
//////        _N=10;//前面的构造函数是没办法对常量进行赋值的
////    }
//
//
////这两个还能混着用
//    data(int year=1,int month=1,int day=1,int i=10086)
//    :_N(10)
//    ,_ref(i)
//    ,_aa(8)
//    {
//        _year=year;
//        _month=month;
//        _day=day;
//    }
//
//
//private:
//    int _year;//在类里面，这里的变量是声明，声明是为了开空间
//    int _month;
//    int _day;
//
//    const int _N;//这里如果是一个常量，那么在10_里面的那种构造函数就没办法进行下去了    不能_N=10;
//    //此外还必须在初始化列表进行初始话的变量
//    int& _ref;//引用是一个       引用的时候必须进行初始化
//    A _aa;//另外一个是没有默认构造函数的自定义类型成员变量           A类没有默认的构造函数
//
//};
////补充一点：常量只有在定义的时候进行初始化
////总结：只有三种类型的变量只能在初始化列表进行初始化      常量，引用，没有默认构造函数的自动以类型成员变量
//
//
//int main(void)
//{
//    B b1(20);
//    data d1(1,2,3,4,b1);
//
//}






//2.自定义类型（有默认构造函数）在初始化列表中初始化和在函数中初始化效率的对比
//class A
//{
//public:
//    A(int a=10086)
//    {
//        _a=a;
//    }
//private:
//    int _a;
//};
//
//
//class data
//{
//public:
////    方式一：
////    data(int year,int month,int day,const A& aa)//
////    {
////    _year=year;
////    _month=month;
////    _day=day;
////    _aa=aa;//虽然没有写初始化列表，但是初始化列表是成员变量定义的1地方，_aa会在初始化列表定义的地方调用默认构造函数
////    }
//
////方式二：
//    data(int year,int month,int day,int a)
//    :_aa2(a)//虽然这个aa2在上面，但是在实际的初始化过程中是先从aa1执行的
//    ,_aa1(_aa2)
//    //所以尽量声明的顺序和初始化列表中的顺序保持一致
//    {
//        _year=year;
//        _month=month;
//        _day=day;
//    }
//
//private:
//    int _year;//在类里面，这里的变量是声明，声明是为了开空间
//    int _month;
//    int _day;
//    A _aa1;//如果参数中有自定义类型的变量，那种定义方式更加高效
//    A _aa2;//第二个变量
//};
//总结：内置类型的成员，在函数体和初始化列表中初始化都是可以的，但是建议在初始化列表中初始化这样更高效
//还有一点，成员变量在类中声明的次序就是在初始化列表中的初始化顺序，与初始化列表中的次序无关








//二、关键字   -----explicit      禁止隐式类型转换的发生
//class data
//{
//public:
////    explicit data(int a=1)      这样就不能直接用=赋值了
//    data(int a=1)
//    {
//        _year=a;
//    }
//
//
//private:
//    int _year;
//};
//
//int main(void)
//{
//    data d1(2022);
//    data d2=2011;//这个就发生了隐式类型转换      是一次构造    一次拷贝构造              并且右值必须类型和_year的类型相同      d2=3.14就不行了
//    //c++在编译器在连续的一个过程中，多个构造会被优化，合二为一，所以在这里被优化为一个构造
//}






//三、匿名对象
//int main(void)//假设这两个类都定义过
//{
//    A a(10);//实例化一个对象
//    data d1(a)//并且d1的构造需要传a对象，就可以这样传
//    data(A(10));   这样的效果就和上面是一样的  就是匿名对象
//}








//四、static成员
//1.概念
//声明为static的类成员称为类的静态变量，用static修饰的成员变量，称之为静态成员变量；用static修饰的成员函数，称之为静态成员函数。静态的成员变量一定要在类外进行初始化

//可用在类构造了多少次


//class A
//{
//public:
//    A(int a=0)
//    :_a(a)
//    {
//        ++_num;
//    }
//
//    A(const A& aa)
//    :_a(aa._a)
//    {
//        ++_num;
//    }
//
//    static int getnum()//静态成员函数没有this指针，只能访问静态成员变量和成员函数
//    {
////        this*->_a//这个类里面的函数没有this指针，也就访问不了类里面的非静态成员函数
//        return _num;
//    }
//
//private:
//    int _a;
//    int _b=4;//c++11新增     如果定义的对象没有进行初始化，这个就和缺省参数作用一样       这里并不是初始化只是声明
//public:
//    static int _num;//静态成员变量属于整个类，所有对象，生命周期在整个程序运行期间
//    //可以理解为某个类专用的，类定义的对象只要有一个进行++ --,整个对象的的num都会改变
//    //构造函数不处理静态成员函数
//};
//
//int A::_num=0;//对静态成员变量进行初始化必须要在类的外面进行
//
//int main(void)
//{
//    A a1(123);
//    A a2(a1);
//
////    cout<<A::_num<<endl;
////    cout<<a1._num<<endl;
////    cout<<a2._num<<endl;//这三种访问的方式是相同的  这样的形式是建立在静态成员变量是共有的基础上
//
//
//    //如果这个num是私有的，就得构造一个访问函数，在外面调用函数才能进行访问
//    cout<<A::getnum()<<endl;
//    cout<<a1.getnum()<<endl;    //也可以通过对象的成员函数去调用
//}